//
// Created by hjie on 23-5-31.
//

#pragma once

#include <cstdint>
#include <cstring>
#include <string>
#include <map>
#include <memory>
#include <sys/types.h>
#include "write_buffer.h"

enum MessageAttrType
{
    EmUserName           = 0x0006,
    EmMessageIntegrity   = 0x0008,
    EmErrorCode          = 0x0009,
    EmLifeTime           = 0x000d,
    EmXorPeerAddress     = 0x0012,
    EmData               = 0x0013,
    EmRealm              = 0x0014,
    EmNONCE              = 0x0015,
    EmXorRelayedAddress  = 0x0016,
    EmRequestedTransport = 0x0019,
    EmXorMappedAddress   = 0x0020,
    EmFingerPrint        = 0x8028,
};

enum EmErrorCode
{
    EmRequestError = 400,
    EmAuthError    = 401,
    EmAttrError    = 420,
};

const static uint32_t magic_cookie = 0x2112a442;
const static uint32_t finger_print = 0x5354554E;

class MessageAttr
{
public:
    MessageAttr(MessageAttrType type);
    virtual ~MessageAttr();
    static std::shared_ptr<MessageAttr> ProcessMessageAttr(const uint8_t * data, int length, int &use_length);
    virtual bool ParseAttr(const uint8_t * data, int length, int & use_length) = 0;
    virtual int GetAttrLength() = 0;
    virtual void ComposeAttr(WriteBuffer & writer) = 0;

    void ComposeBase(WriteBuffer & writer);
    MessageAttrType MsgAttrType() { return m_attr_type; }
    void SetAttrType(MessageAttrType type) { m_attr_type = type; }
    void PaddingData(WriteBuffer & writer, int padding_size);
protected:
    MessageAttrType m_attr_type;
    uint16_t m_length;
};


class AttrXorMappedAddress : public MessageAttr
{
public:
    AttrXorMappedAddress();
    virtual ~AttrXorMappedAddress(){};
    virtual bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    virtual int  GetAttrLength() override;
    virtual void ComposeAttr(WriteBuffer & writer) override;
    virtual void ParseAddrInfo(int protocol_type, const struct sockaddr * addr, int length);
    std::string LocalIp();
    uint16_t LocalPort();
    uint16_t DecoderPort();
    uint16_t EncoderPort();
    uint32_t EncoderAddr();
    std::string DecoderAddr();
    
public:
    uint8_t  m_protocol;
    uint16_t m_port;
    uint32_t m_addr;
};

class AttrRequestedTransport : public  MessageAttr
{
public:
    AttrRequestedTransport();
    virtual ~AttrRequestedTransport() = default;
    virtual bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    virtual int  GetAttrLength() override;
    virtual void ComposeAttr(WriteBuffer & writer) override;
    std::string RequestTransport() { return m_request_transport; }
    void SetTransport(const std::string & method);
private:
    std::string m_request_transport;
};

class AttrRealm : public MessageAttr
{
public:
    AttrRealm();
    virtual ~AttrRealm(){}
    virtual bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    virtual int  GetAttrLength() override;
    virtual void ComposeAttr(WriteBuffer & writer) override;
    std::string Realm() { return m_realm; }
    void SetRealm(const std::string & realm);
private:
    std::string m_realm;
};

class AttrErrorCode : public MessageAttr
{
public:
    AttrErrorCode();
    virtual ~AttrErrorCode(){}
    virtual bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    virtual int  GetAttrLength() override;
    virtual void ComposeAttr(WriteBuffer & writer) override;
    int GetErrorClass() {   return m_error_class; }
    int GetErrorCode()  {   return m_error_code;  }
    void SetError(uint8_t error_class, uint8_t error_code);
private:
    uint8_t m_error_class;
    uint8_t m_error_code;
};

class AttrNonce : public MessageAttr
{
public:
    AttrNonce();
    virtual ~AttrNonce(){}
    virtual bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    virtual int  GetAttrLength() override;
    virtual void ComposeAttr(WriteBuffer & writer) override;
    void SetNonce(const std::string & data);
    std::string GetNonceData() { return m_nonce_data; }
private:
    std::string m_nonce_data;
};


class AttrUserName : public MessageAttr
{
public:
    AttrUserName();
    ~AttrUserName() = default;
public:
    bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    virtual void ComposeAttr(WriteBuffer & writer) override;
    int GetAttrLength() override;
    void SetUserName(const std::string & user_name);
private:
    std::string m_user_name;
};


class AttrLifeTime : public MessageAttr
{
public:
    AttrLifeTime();
    ~AttrLifeTime() = default;
public:
    bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    virtual void ComposeAttr(WriteBuffer & writer) override;
    int GetAttrLength() override;
    int GetLifeTime();
public:
    uint32_t m_left_time;
};


class AttrData : public MessageAttr
{
public:
    AttrData();
    ~AttrData();
public:
    bool ParseAttr(const uint8_t  * data, int length, int & use_length) override;
    void ComposeAttr(WriteBuffer & writer) override;
    int GetAttrLength() override;
    void PushData(const uint8_t * data, int length);
public:
    std::vector<uint8_t> m_data_vec;
};

class AttrCrc32 : public MessageAttr
{
public:
    AttrCrc32();
    ~AttrCrc32();
public:
    bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    void ComposeAttr(WriteBuffer & writer) override;
    int  GetAttrLength() override;
    uint32_t Crc32();
    bool CheckCrc32Data(const uint8_t * data, int length);
    void ComputeCrc32(uint8_t   * data, int length);
public:
    uint32_t m_crc32_data{0};
};


class AttrMessageIntegrity : public MessageAttr
{
public:
    AttrMessageIntegrity();
    ~AttrMessageIntegrity();
public:
    bool ParseAttr(const uint8_t * data, int length, int & use_length) override;
    void ComposeAttr(WriteBuffer & writer) override;
    int  GetAttrLength() override;
    void SetHmacKey(const std::string & key);
    bool CheckHmacData(const uint8_t * data, int length);
    bool CheckHmacData(const uint8_t * data, int length, const std::string & key);
private:
    std::string m_hmac_key;
    unsigned char m_hmac_data[20];
};




